#include <common.h>
#include <idt.h>
#include <thread.h>
#include <gdt.h>
#include <process.h>

idt_entry idt[256];
idt_descriptor idt_ptr;
interrupt_handler int_handlers[256];

void idt_set_gate(unsigned char num, unsigned int base, unsigned short selector, unsigned short flags)
{
	idt[num].base_lower = base & 0xFFFF;
	idt[num].base_upper = (base>>16)&0xFFFF;
	idt[num].selector = selector;
	idt[num].flags = flags | 0x60;
}

void init_idt()
{
	memset(&int_handlers, 0, sizeof(interrupt_handler)*256);
	idt_ptr.size = sizeof(idt_entry)*256 - 1;
	idt_ptr.offset = (unsigned int) &idt;
	memset(&idt, 0, sizeof(idt_entry)*256);
	
	outb(0x20, 0x11);
	outb(0xA0, 0x11);
	outb(0x21, 0x20);
	outb(0xA1, 0x28);
	outb(0x21, 0x04);
	outb(0xA1, 0x02);
	outb(0x21, 0x01);
	outb(0xA1, 0x01);
	outb(0x21, 0x0);
	outb(0xA1, 0x0);
	
	idt_set_gate(0, (unsigned int)isr0, 0x08, 0x8E);
	idt_set_gate(1, (unsigned int)isr1, 0x08, 0x8E);
	idt_set_gate(2, (unsigned int)isr2, 0x08, 0x8E);
	idt_set_gate(3, (unsigned int)isr3, 0x08, 0x8E);
	idt_set_gate(4, (unsigned int)isr4, 0x08, 0x8E);
	idt_set_gate(5, (unsigned int)isr5, 0x08, 0x8E);
	idt_set_gate(6, (unsigned int)isr6, 0x08, 0x8E);
	idt_set_gate(7, (unsigned int)isr7, 0x08, 0x8E);
	idt_set_gate(8, (unsigned int)isr8, 0x08, 0x8E);
	idt_set_gate(9, (unsigned int)isr9, 0x08, 0x8E);
	idt_set_gate(10, (unsigned int)isr10, 0x08, 0x8E);
	idt_set_gate(11, (unsigned int)isr11, 0x08, 0x8E);
	idt_set_gate(12, (unsigned int)isr12, 0x08, 0x8E);
	idt_set_gate(13, (unsigned int)isr13, 0x08, 0x8E);
	idt_set_gate(14, (unsigned int)isr14, 0x08, 0x8E);
	idt_set_gate(15, (unsigned int)isr15, 0x08, 0x8E);
	idt_set_gate(16, (unsigned int)isr16, 0x08, 0x8E);
	idt_set_gate(17, (unsigned int)isr17, 0x08, 0x8E);
	idt_set_gate(18, (unsigned int)isr18, 0x08, 0x8E);
	idt_set_gate(19, (unsigned int)isr19, 0x08, 0x8E);
	idt_set_gate(20, (unsigned int)isr20, 0x08, 0x8E);
	idt_set_gate(21, (unsigned int)isr21, 0x08, 0x8E);
	idt_set_gate(22, (unsigned int)isr22, 0x08, 0x8E);
	idt_set_gate(23, (unsigned int)isr23, 0x08, 0x8E);
	idt_set_gate(24, (unsigned int)isr24, 0x08, 0x8E);
	idt_set_gate(25, (unsigned int)isr25, 0x08, 0x8E);
	idt_set_gate(26, (unsigned int)isr26, 0x08, 0x8E);
	idt_set_gate(27, (unsigned int)isr27, 0x08, 0x8E);
	idt_set_gate(28, (unsigned int)isr28, 0x08, 0x8E);
	idt_set_gate(29, (unsigned int)isr29, 0x08, 0x8E);
	idt_set_gate(30, (unsigned int)isr30, 0x08, 0x8E);
	idt_set_gate(31, (unsigned int)isr31, 0x08, 0x8E);
	idt_set_gate(32, (unsigned int)irq0, 0x08, 0x8E);
	idt_set_gate(33, (unsigned int)irq1, 0x08, 0x8E);
	idt_set_gate(34, (unsigned int)irq2, 0x08, 0x8E);
	idt_set_gate(35, (unsigned int)irq3, 0x08, 0x8E);
	idt_set_gate(36, (unsigned int)irq4, 0x08, 0x8E);
	idt_set_gate(37, (unsigned int)irq5, 0x08, 0x8E);
	idt_set_gate(38, (unsigned int)irq6, 0x08, 0x8E);
	idt_set_gate(39, (unsigned int)irq7, 0x08, 0x8E);
	idt_set_gate(40, (unsigned int)irq8, 0x08, 0x8E);
	idt_set_gate(41, (unsigned int)irq9, 0x08, 0x8E);
	idt_set_gate(42, (unsigned int)irq10, 0x08, 0x8E);
	idt_set_gate(43, (unsigned int)irq11, 0x08, 0x8E);
	idt_set_gate(44, (unsigned int)irq12, 0x08, 0x8E);
	idt_set_gate(45, (unsigned int)irq13, 0x08, 0x8E);
	idt_set_gate(46, (unsigned int)irq14, 0x08, 0x8E);
	idt_set_gate(47, (unsigned int)irq15, 0x08, 0x8E);
	idt_set_gate(255, (unsigned int)isr255, 0x08, 0x8E);
	
	idt_flush((unsigned int)&idt_ptr);
}

unsigned char stacks[16];

void free_stack(unsigned int i)
{
	unsigned int stack_num;
	unsigned int esp;
//	asm volatile ("mov %%esp, %0" : "=r" (esp));
//	if(esp >= 0xD0000000)
//	{
//	esp = esp & ~0xFFF;
//	printf("\nFree stack %x", esp);
//	esp = 0xE0000000 - esp;
//	stack_num = esp/0x1000;
//	stacks[stack_num-1] = 0;
//	}
	stacks[i] = 0;
}

unsigned int get_next_stack()
{
	unsigned int i = 0;
	while(i < 16)
	{
		if(stacks[i] == 0)
			break;
		i++;
	}
	stacks[i] = 1;
//	global_tss.esp0 = 0xE0000000 - (i*0x1000);
	printf("\nnext_stack %x", 0xE0000000 - (i*0x1000),global_tss.esp0);
	return i;
}

registers *idt_handler(registers *r)
{
	if (int_handlers[r->int_no])
	{
		int_handlers[r->int_no](r);
	}
	else
	{
		unsigned int cr3; asm volatile ("mov %%cr3, %0": "=r" (cr3));
		printf("Unhandled interrupt no: %d Code:%x\n At:%x - %s %x\n",r->int_no,r->err_no, r->eip, panic_lookup(r->eip), cr3);
		panic("Fault!");
		for(;;);
	}
	global_tss.esp0 = (unsigned int)&current_thread->test.v86es;
//	if(current_thread->process->pid == 0x3)
//		BREAK
	return r;
}
void *irq_handler(registers *r)
{

	if (int_handlers[r->int_no])
	{
		int_handlers[r->int_no](r);
	}

	if(r->int_no >= 40)
	{
		outb(0xA0,0x20);
	}
	outb(0x20,0x20);
	global_tss.esp0 = (unsigned int)&current_thread->test.v86es;
	return r;
}

void register_int_handler(unsigned char num, interrupt_handler handler)
{
	int_handlers[num] = handler;
}
